#include "Common.fx"

//--------------------------------------
struct a2v {
	a2vApplyBasic basic;
};

struct v2f {
	v2fApplyBasic basic;
};

//--------------------------------------
sampler ProjLightMapSamp : register(s2);
sampler ShadowMapSamp : register(s3);

const float g_VsmEpsilon = 0.00005f;

//--------------------------------------
v2f vsMain(a2v input) {
	
	v2f output;
	
	ApplyBasicVertexProcess(output.basic, input.basic);
	
	return output;
}

//--------------------------------------
f2fb psMain(v2f input) {

	f2fb output;
	
	input.basic.lsPos.xy /= input.basic.lsPos.w;
	input.basic.lsPos.xy = saturate(input.basic.lsPos.xy);
	
	float4 lightMap = tex2D(ProjLightMapSamp, input.basic.lsPos.xy);
	
	if(input.basic.lsPos.z < 0.01)
		lightMap = 0;
	
	float2 smTexcoord;
	ShadowMapBaseTexcoord(smTexcoord, input.basic.lsPos.xy);
	float4 moments = tex2D(ShadowMapSamp, smTexcoord);
	
	float shadowTerm;
	
	if(input.basic.lsPos.z < moments.x)
	{
		shadowTerm = 1.0;
	}
	else
	{
		float E_x2		= moments.y;
		float Ex_2		= moments.x * moments.x;
		//float variance	= min( 1.0, max(0.0, E_x2 - Ex_2 + g_VsmEpsilon) );
		float variance	= E_x2 - Ex_2 + g_VsmEpsilon;
		//float variance	= E_x2 - Ex_2;
		float d			= moments.x - input.basic.lsPos.z;
		float p			= variance / (variance + d * d);
		
		shadowTerm = p;
	}
	
	lightMap *= shadowTerm;
	
	ApplyBasicFragmentProcess(output.c0, input.basic, lightMap);
	
	return output;
}

//--------------------------------------
technique Apply {

	pass {
	
		AlphaBlendEnable	= false;
		AlphaTestEnable		= false;
		
		MagFilter[3]		= Linear;
		MinFilter[3]		= Linear;
		
		VertexShader		= compile vs_3_0 vsMain();
		PixelShader			= compile ps_3_0 psMain();
	}
}

//--------------------------------------